package testing;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.LinkedList;
import java.util.Random;

import com.thesis.algorithm.Device;
import com.thesis.algorithm.FileConverter;
import com.thesis.algorithm.Sequence;
import com.thesis.algorithm.SequenceElement;
import com.thesis.algorithm.SequenceMatching;
import com.thesis.utils.BusControl;
import com.thesis.utils.CONSTANTS;
import com.thesis.utils.VelocityEstimateSequence;
import com.thesis.utils.VelocityEstimateTest;
import com.thesis.utils.myWriter;

public class VelocityEstimateSequenceWrapper {
	LinkedList<Sequence> _TESTDATA = new LinkedList<Sequence>();
	SequenceMatching sm = new SequenceMatching(
			SequenceMatching.MODE_READ_FROM_TRAINFOLDER);
	BusControl busController;
	LinkedList<VelocityEstimateTest> vet;
	int noOfbusReturn = 4;

	public VelocityEstimateSequenceWrapper() {
		busController = new BusControl();
		FileConverter fc = new FileConverter(CONSTANTS.TEST_DATA_FOLDER);
		_TESTDATA = busController.produceTrainSequence(fc.listOfDevices);
		for (int i = 0; i < _TESTDATA.size(); i++) {
			System.out.println("TESTDATA" + _TESTDATA.get(i).BusRouteID + " "
					+ _TESTDATA.get(i).size());
		}

		vet = new LinkedList<VelocityEstimateTest>();
		VelocityEstimateTest tmpvet;
		for (Device d : fc.listOfDevices) {
			tmpvet = new VelocityEstimateTest(d);
			vet.add(tmpvet);
		}
	}

	public void testSequenceAndPrintToFile(int sequence_length,
			Writer outSummary, Writer outExcel) throws IOException {

		Writer out2 = new BufferedWriter(new OutputStreamWriter(
				new FileOutputStream(CONSTANTS.RESULT_FOLDER
						+ "testSequenceAndPrintToFile" + sequence_length
						+ ".txt"), "UTF-8"));
		myWriter out = new myWriter(out2);

		Random randomGenerator = new Random();
		double finalsteps = 0;
		int allcount = 0;
		int stepcount = 0;
		double SumDiffAll = 0;
		double allMax = 0;
		double allMin = 5000;
		double stepMax = 0;
		double stepMin = 5000;
		double SumDiffSteps = 0;
		double all = 0;
		double GPSv = 0;

		outExcel.write("GPSv\tall\tfinalsteps\tMath.abs(GPSv - all)\tMath.abs(GPSv - finalsteps)\n");
		for (int i = 0; i < CONSTANTS.nExample; i++) {

			// test data
			int fileindex = randomGenerator.nextInt(_TESTDATA.size()) - 1;
			if (fileindex == -1) {
				fileindex = 0;
			}

			int start = randomGenerator.nextInt(_TESTDATA.get(fileindex).size()
					- sequence_length - 1);
			Sequence testdata = new Sequence();
			for (int j = start; j < start + sequence_length; j++) {
				testdata.add(new SequenceElement(_TESTDATA.get(fileindex)
						.get(j)));
				testdata.getLast().Repetition = 1;
			}

			System.out.println("TEST " + (i + 1));
			out.writeln("TEST: " + i);
			out.writeln("TESTDATA: " + testdata.toString());
			out.writeln("from" + start);
			out.writeln("TEST REFINED: " + testdata.refineSequence().toString());
			out.writeln("BUSROUTE: " + _TESTDATA.get(fileindex).BusRouteID);

			// hide the state
			testdata.BusRouteID = _TESTDATA.get(fileindex).BusRouteID;
			VelocityEstimateSequence ves = new VelocityEstimateSequence(
					this.busController);
			ves.Add(testdata, (short) testdata.BusRouteID);
			for (int j = 0; j < testdata.sequenceinFile.size(); j++) {
				testdata.get(j).State = 0;
			}
			out.writeln("TEST REFINED:" + testdata.refineSequence().toString());
			out.writeln("containsOnlyOneRoute: " + sm.containsOnlyOneRoute
					+ "  - " + sm.singleInterestedRoute);
			Sequence seq = sm.matchAndReturnSequence(testdata, out2,
					CONSTANTS.ALLBUSROUTE);
			double[] tmp = testVelocity(seq, outSummary, outExcel, fileindex,
					start);
			// sm.matchBusStop(testdata, out2, CONSTANTS.ALLBUSROUTE);
			// out.writeln("Score" + seq.score() +" "+ seq.toString());
			all = ves.returnVelocity(this.noOfbusReturn)*3600;
			GPSv = tmp[0];
			finalsteps = tmp[1];

			outExcel.write(GPSv + "\t" + all + "\t" + finalsteps + "\t "
					+ Math.abs(GPSv - all) + "\t" + Math.abs(GPSv - finalsteps)
					+ "\n");

			if (all > 0.000001) {
				SumDiffAll += Math.abs(GPSv - all);
				allcount++;
				if (Math.abs(GPSv - all) > allMax) {
					allMax = Math.abs(GPSv - all);
				}
				if (Math.abs(GPSv - all) < allMin) {
					allMin = Math.abs(GPSv - all);
				}
			}
			if (finalsteps > 0.000001) {
				SumDiffSteps += Math.abs(GPSv - finalsteps);
				stepcount++;
				if (Math.abs(GPSv - finalsteps) > stepMax) {
					stepMax = Math.abs(GPSv - finalsteps);
				}
				if (Math.abs(GPSv - finalsteps) < stepMin) {
					stepMin = Math.abs(GPSv - finalsteps);
				}
			}
			out2.write("\n\n\n\n");
		}
		outExcel.write("ALL MIN      :" + allMin + "\n");
		outExcel.write("ALL MAX      :" + allMax + "\n");
		outExcel.write("ALL AVG      :" + (SumDiffAll / allcount) + "\n");
		outExcel.write("STEP MIN      :" + stepMin + "\n");
		outExcel.write("STEP MAX      :" + stepMax + "\n");
		outExcel.write("STEP AVG      :" + (SumDiffSteps / stepcount) + "\n");
		outExcel.close();

		out.writeln("Number of test: " + CONSTANTS.nExample);
		out.close();
	}

	private double[] testVelocity(Sequence sequence, Writer out,
			Writer outExcel, int fileIndex, int start) throws IOException {
		VelocityEstimateSequence ves = new VelocityEstimateSequence(
				busController);
		ves.Add(sequence, (short) sequence.BusRouteID);
		double vCell = ves.returnVelocity(this.noOfbusReturn);

		double vGPS = vet.get(fileIndex).returnVelocity(
				start + ves.lastTimeStamp, start + sequence.score());

		out.write("vCell: " + vCell * 3600 + "\n");
		out.write("vGPS: " + vGPS * 3600 + "\n");
		out.write("vDiff: " + (vCell * 3600 - vGPS * 3600) + "\n");
		out.write("start: " + start + "\n");
		out.write("last: " + ves.lastTimeStamp + "\n");
		out.write("score: " + sequence.score() + "\n\n\n");
		return new double[] { vGPS *3600, vCell*3600 };
	}
}
